/*
 * @Descripttion: 手写promise
 * @version: 1.0.0
 * @Author: 某人
 * @Date: 2021-09-14 16:55:48
 */
// 新建一个类
// https://juejin.cn/post/6844903989058748429
function promise (executor) {
  // 初始化state为等待状态
  this.state = 'pending'
  // 成功的值
  this.value = undefined
  // 失败的原因
  this.reason = undefined
  // 存放fn1的回调
  this.fn1Callbacks = []
  // 存放fn2的回调
  this.fn2Callbacks = []
  // 成功
  let resolve = (value) => {
    if (this.state = 'pending') {
      this.state = 'fulfilled'
      this.value = value
    }
  }
  // 失败
  let reject = (reason) => {
    if (this.state = 'pending') {
      this.state = 'rejected'
      // 存储失败的原因
      this.reason = reason
    }
  }
  // 立即执行
  try {
    executor(resolve, reject)
  } catch (error) {
    reject(error)
  }
}
promise.prototype.then = function(fn1, fn2) {
  let self = this
  let promise2

  // 首先对入参 fn1, fn2做判断
  fn1 = typeof fn1 === 'function' ? fn1 : function (v) {}
  fn2 = typeof fn2 === 'function' ? fn1 : function (r) {}
  // 如果promise的状态是resolved，需要执行fn1
  if (self.status === 'resolved') {
    return promise2 = new promise(function(resolve, reject) {
      // TODO:fn1执行后会有返回值，通过resolve注入到then返回的promise中
      try {
        let x = fn1(self.data)
        if(x instanceof Promise) {
          // 如果是一个promise对象，需要等待promise状态变化拿到fullfilled的值才会继续执行
          x.then((data) => {
            resolve(data)
          }), (e) => {
            reject(e)
          }
        } else if (typeof x.then === 'function') {
          // 如果是一个thenable对象
          x.then(function (y) {
            resolve(y)
          })
        } else {
          resolve(x)
        }
        
      } catch(e) {
        reject(e)
      }
    })
  }
  // 如果promise的状态是rejected 需要执行fn2
  if(self.status === 'rejected') {
    return promise2 = new promise(function (resolve, reject) {
      // TODO:
      try {
        let x = fn2(self.data)
        // fn1执行后会有发回执，通过resolve注入到then返回的promise中
        reject(x)
      } catch (e) {
        reject(e)
      }
    })
  }
  // 如果promise的状态是pending，我们并不能确定调用fn1还是fn2，只能先把方法都保存在fn1Callback,fn2callback数组中，等到Promise状态确定后在处理
  if (self.status === 'pending') {
    return promise2 = new promise(function (resolve, reject) {
      new Promise(function (resolve, reject) {
        this.fn1Callbacks.push(function (value) {
          try {
            let x = fn1(self.data)
            resolve(x)
          } catch (e) {
            reject(e)
          }
        })
        this.fn2Callbacks.push(function (value) {
          try {
            let x = fn2(self.data)
            reject(x)
          } catch (e) {
            reject(e)
          }
        })
      })
    })
  }
}
function resolvePromise(promise2, x, resolve, reject) {
  // 为了防止循环引用
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'))
  }
  // 如果x是promise
  if (x instanceof Promise) {
    x.then(function (data) {
      resolve(data)
    }, function (e) {
      reject(e)
    })
    return
  }
  // 如果x是object或者是function
  if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {
    // 拿 x.then可能会报错
    try {
      // 先拿到x.then
      let then = x.then
      let called
      if (typeof then === 'function') {
        // 这里的写法， 是then.call(this, fn1, fn2)
        then.call(x, (y) => {
          // called的作用：
          // 有一些promise实现的不是很规范，为了保证fn1和fn2只能调用一个 会这支一个called标志位置
          if (called) {
            return
          }
          called = true
          return resolvePromise(promise2, y, resolve, reject)
        }, (r) => {
          if (called) {
            return
          }
          called = true
          return reject(r)
        })
      }
    } catch(e) {
      if (called) {
        return
      }
      called = true
      return reject(r)
    }
  } else {
    resolve(x)
  }
}